package com.example.springbootbabyu.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Date;
import java.util.concurrent.TimeUnit;
@Slf4j
public class JwtTokenUtil {

    private final Algorithm algorithm;
    private final StringRedisTemplate redisTemplate;
    private final long expire;

    private static final String REDIS_PREFIX = "jwt:";
    private static final String CLAIM_USER_ID = "userId";
    private static final String CLAIM_USERNAME = "username";

    public JwtTokenUtil(Algorithm algorithm, StringRedisTemplate redisTemplate, long expire) {
        this.algorithm = algorithm;
        this.redisTemplate = redisTemplate;
        this.expire = expire;
    }

    /**
     * 生成Token
     */
    public String generateToken(String userId, String username) {
        Date now = new Date();
        Date expireDate = new Date(now.getTime() + expire * 1000);

        String token = JWT.create()
                .withClaim(CLAIM_USER_ID, userId)
                .withClaim(CLAIM_USERNAME, username)
                .withIssuedAt(now)
                .withExpiresAt(expireDate)
                .sign(algorithm);

        // 存储到Redis中
        String redisKey = getRedisKey(userId, token);
        redisTemplate.opsForValue().set(redisKey, token, expire, TimeUnit.SECONDS);

        return token;
    }

    /**
     * 验证Token
     */
    public boolean validateToken(String token) {
        try {
            // 验证JWT签名和过期时间
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);

            // 从JWT中获取用户ID
            String userId = jwt.getClaim(CLAIM_USER_ID).asString();
            log.info("userId: {}", userId);
            if (userId == null) {
                return false;
            }
            // 检查Redis中是否存在该token
            String redisKey = getRedisKey(userId, token);
            log.info("redisKey: {}", redisKey);
            String redisToken = redisTemplate.opsForValue().get(redisKey);
            log.info("redisToken: {}", redisToken);
            return StringUtils.isNotBlank(redisToken) && redisToken.equals(token);
        } catch (JWTVerificationException e) {
            return false;
        }
    }

    /**
     * 从Token中获取用户ID
     */
    /**
     * 清理 Token，移除 "Bearer " 前缀
     */
    public String cleanToken(String token) {
        if (token == null) return null;
        return token.replace("Bearer ", "").trim();
    }

    /**
     * 从原始头部值获取用户ID
     */
    public String getUserIdFromAuthHeader(String authHeader) {
        return getUserIdFromToken(cleanToken(authHeader));
    }

    /**
     * 核心方法：从纯净 token 获取用户ID
     */
    public String getUserIdFromToken(String token) {
        token = cleanToken(token);
        if (token == null) {
            return null;
        }
        try {
            DecodedJWT jwt = JWT.decode(token);
            log.info("jwt: {}", jwt);
            return jwt.getClaim(CLAIM_USER_ID).asString();
        } catch (Exception e) {
            log.error("getUserIdFromToken error: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从Token中获取用户名
     */
    public String getUsernameFromToken(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(CLAIM_USERNAME).asString();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 删除Token
     */
    public void deleteToken(String token) {
        String userId = getUserIdFromToken(token);
        if (userId != null) {
            String redisKey = getRedisKey(userId, token);
            redisTemplate.delete(redisKey);
        }
    }

    /**
     * 刷新Token过期时间
     */
    public void refreshToken(String token) {
        String userId = getUserIdFromToken(token);
        log.info("userId: {}", userId);
        if (userId != null) {
            String redisKey = getRedisKey(userId, token);
            redisTemplate.expire(redisKey, expire, TimeUnit.SECONDS);
        }
    }

    private String getRedisKey(String userId, String token) {
        return REDIS_PREFIX + userId + ":" + token;
    }
}